#include "Util.h"
#include <cctype>
#include <csignal>
#include <cstddef>
#include <cstring>
#include <string>
#include <sys/stat.h>
#include <sys/timerfd.h>
#include <sys/types.h>
#include <unistd.h>
#include "PlatLogger.h"
#include "XnccType.h"

namespace xncc {
namespace shared {
    __thread char t_errnobuf[512];

    const char* strerror_tl(int savedErrno) { return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); }

    std::string getDisconnectedReason(int err)
    {
        switch (err) {
            case 0: {
                return "0|success";
                break;
            }
            case -1: {
                return "-1|tcp message len too big";
                break;
            }
            case -2: {
                return "-2|kick connection";
                break;
            }
            default: {
                std::string reason = std::to_string(err) + "|";
                reason += strerror_tl(err);
                return reason;
            }
        }
    }

    std::atomic<int64_t> CommonBusi::gSeqNo(1);
    int64_t              CommonBusi::generateSeqNo() { return gSeqNo.fetch_add(1); }

    std::atomic<types::connection_id_t> CommonBusi::gConnId(1);

    auto CommonBusi::generateConnId() -> types::connection_id_t
    {
        auto connId = gConnId.fetch_add(1);
        if (connId == types::FROM_OTHER_THREAD) {
            gConnId = 1;
            return 1;
        }
        return connId;
    }

    int CommonBusi::createTimerfd()
    {
        int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
        if (timerfd < 0) {
            throw system_exception("create timerfd failed");
        }
        return timerfd;
    }

    bool CommonBusi::isIpV4(const std::string& ip)
    {
        /// 长度小于7开头或结尾为.都返回false
        if (ip.size() < 7 || ip[0] == '.' || ip[ip.size() - 1] == '.') {
            return false;
        }
        std::vector<std::string> str = StrBusi::split(ip, ".");
        // 切割后的长度不够4返回false
        if (str.size() != 4) {
            return false;
        }
        for (auto& i : str) {
            if (i.size() == 0 || (i.size() > 1 && i[0] == '0') || i.size() > 3) {
                return false;
            }
            int num = 0;  // 转换数字
            for (char c : i) {
                /// 必须是数字
                if (c < '0' || c > '9') {
                    return false;
                }
                num = num * 10 + (c - '0');
                // 范围0-255,不能超过255
                if (num > 255) {
                    return false;
                }
            }
        }
        return true;
    }
    bool CommonBusi::isIpV6(const std::string& ip)
    {
        // 格式为X:X:X:X:X:X:X:X，其中每个X表示地址中的16b，以十六进制表示
        if (ip.size() < 15 || ip[0] == ':' || ip[ip.size() - 1] == ':') {
            return false;
        }
        std::vector<std::string> str = StrBusi::split(ip, ":");

        // 切割后的长度不够8返回false
        if (str.size() != 8) {
            return false;
        }
        for (auto& i : str) {
            if (i.size() == 0 || i.size() > 4) {
                return false;
            }
            for (char c : i) {
                /// 必须是数字或字母
                if ((c < 'a' || c > 'f') && (c < 'A' || c > 'F') && (c < '0' || c > '9')) {
                    return false;
                }
            }
        }
        return true;
    }

    int CommonBusi::setCpuAffinity(int coreId)
    {
        auto numCores = sysconf(_SC_NPROCESSORS_ONLN);
        if (coreId < 0 || coreId >= static_cast<int>(numCores)) {
            return -1;
        }
        cpu_set_t cpuSet;
        CPU_ZERO(&cpuSet);
        CPU_SET(coreId, &cpuSet);
        pthread_t current = pthread_self();
        return pthread_setaffinity_np(current, sizeof(cpu_set_t), &cpuSet);
    }

    void FileBusi::createPath(const std::string& spath)
    {
        const char* path   = spath.c_str();
        int         length = static_cast<int>(strlen(path));
        std::string createPath;
        for (const char* pos = path; (pos - path) <= length; ++pos) {
            createPath += *pos;
            if (*pos == '/' || (pos - path) == length) {
                mkdir(createPath.c_str(), 0777);
            }
        }
    }

    std::string FileBusi::appendPath(const std::string& path, const std::string& file)
    {
        const char last = path.back();
        if (last == '/') {
            return std::string(path) + file;
        }
        return std::string(path) + '/' + file;
    }

    bool FileBusi::exists(const std::string& file)
    {
        if (file.empty()) {
            return false;
        }
        struct stat fst = {};
        return ::stat(file.data(), &fst) == 0;
    }

    bool FileBusi::isLink(const std::string& file) { return isSpecificMode(file, S_IFLNK); }

    bool FileBusi::isDirectory(const std::string& file) { return isSpecificMode(file, S_IFDIR); }

    bool FileBusi::isFile(const std::string& file) { return isSpecificMode(file, S_IFREG); }

    void FileBusi::remove(const std::string& file)
    {
        int ret = 0;
        if (!isLink(file) && isDirectory(file)) {
            ret = rmdir(file.data());
        }
        else {
            ret = unlink(file.data());
        }
        if (ret != 0) {
            SYSTEM_ERROR << ("remove file"_s) << file;
        }
    }

    bool FileBusi::isSpecificMode(const std::string& file, mode_t mode)
    {
        if (file.empty()) {
            return false;
        }
        struct stat fst = {};
        if (::stat(file.data(), &fst) == 0) {
            return (((fst.st_mode) & S_IFMT) == (mode));
        }
        return false;
    }

    std::vector<std::string> StrBusi::split(const std::string& str, const std::string& pattern)
    {
        std::vector<std::string> ret;
        if (pattern.empty()) {
            return ret;
        }
        size_t start = 0;
        size_t index = str.find_first_of(pattern, 0);
        while (index != std::string::npos) {
            if (start != index) {
                ret.push_back(str.substr(start, index - start));
            }
            start = index + 1;
            index = str.find_first_of(pattern, start);
        }
        if (!str.substr(start).empty()) {
            ret.push_back(str.substr(start));
        }
        return ret;
    }

    std::string StrBusi::toUpper(const std::string& str)
    {
        std::string result = str;
        for (std::size_t i = 0; i < str.size(); ++i) {
            result[i] = static_cast<char>(toupper(static_cast<int>(str[i])));
        }
        return result;
    }
    std::string StrBusi::toLower(const std::string& str)
    {
        std::string result = str;
        for (std::size_t i = 0; i < str.size(); ++i) {
            result[i] = static_cast<char>(tolower(static_cast<int>(str[i])));
        }
        return result;
    }

}  // namespace shared
}  // namespace xncc